#pragma once
#include <iostream>
#include <string>
#include <cstring>

namespace ns_protocol
{
#define MYSELF 1
#define SPACE " "
#define SPACE_LEN strlen(SPACE)

#define SEP "\r\n"
#define SEP_LEN strlen(SEP) // 不能是sizeof  它会把\0也算上

    class Request
    {
    public:
        // 1. 自主实现 "lenth\r\nx_ op_ y_\r\n"
        // 2.使用线程的方案
        std::string Serialize()
        {
#ifdef MYSELF
            std::string str;
            str = std::to_string(x_);
            str += SPACE;
            str += op_; // TODO
            str += SPACE;
            str += std::to_string(y_);
            return str;
#else
            std::cout << "TODO" << std::endl;
#endif
        }

        // "x_ op_ y_"   1234 + 2345
        bool Deserialized(const std::string &str)
        {
#ifdef MYSELF
            std::size_t left = str.find(SPACE);
            if (left == std::string::npos)
                return false;
            std::size_t right = str.rfind(SPACE);
            if (right == std::string::npos)
                return false;
            x_ = atoi(str.substr(0, left).c_str());
            y_ = atoi(str.substr(right + SPACE_LEN).c_str());
            if (left + SPACE_LEN > str.size())
                return false;
            op_ = str[left + SPACE_LEN];
#else
            std::cout << "TODO" << std::endl;
#endif
        }

    public:
        Request()
        {
        }

        Request(int x, int y, char op)
            : x_(x), y_(y), op_(op)
        {
        }

        ~Request() {}

    public:
        int x_;   // 是什么？
        int y_;   // 是什么？    约定
        char op_; // + - * / %
    };

    class Respense
    {
    public:
        // "code_ result_"
        std::string Serialize()
        {
#ifdef MYSELF
            std::string s;
            s = std::to_string(code_);
            s += SPACE;
            s += std::to_string(result_);

            return s;
#else
            std::cout << "TODO" << std::endl;
#endif
        }

        // "1 0"
        bool Deserialized(const std::string &s)
        {
#ifdef MYSELF
            std::size_t pos = s.find(SPACE);
            if (pos == std::string::npos)
                return false;
            code_ = atoi(s.substr(0, pos).c_str());
            result_ = atoi(s.substr(pos + SPACE_LEN).c_str());
            return true;
#else
            std::cout << "TODO" << std::endl;
#endif
        }

    public:
        Respense()
        {
        }

        Respense(int result, int code)
            : result_(result), code_(code)
        {
        }
        ~Respense() {}

    public:
        // result_? code_? 0?1?2?3?      ->  表示约定
        int result_; // 计算结果
        int code_;   // 计算结果的状态码
    };

    // 临时方案
    // 调整方案2：我门期望，你必须给我返回一个完整的报文
    bool Recv(int sock, std::string *out)
    {
        // UDP 是面向数据报的
        // TCP 面向字节流的
        // Recv 你怎么保证，你读到的inbuffer，是一个完整完善的请求呢？
        // "1234 + 5678" : 1234 +
        // "1234 + 5678" : 1234 + 5678 123+99
        // 必须是："1234 + 5678" 这样的完整报文  ---- recv是不能保证的
        // 单纯的recv是无法解决这个问题的，我们需要对协议进一步定制

        // 自主实现  "lenth\r\nx_ op_ y_\r\nlenth\r\nx_ op_ y_\r\nlenth\r\nx_ op_ y_\r\n"
        // 我读到了\r\n，就证明前面的是lenth,而且lenth一定是整型
        // 9        完整报文就是 9\r\n123 + 456\r\n
        // 123 + 456
        char buffer[1024];
        ssize_t s = recv(sock, buffer, sizeof(buffer) - 1, 0); // 9\r\n123+789\r\n
        if (s > 0)
        {
            buffer[s] = 0;
            *out += buffer;
        }
        else if (s == 0)
        {
            //std::cout << "client quit" << std::endl;
            return false;
        }
        else
        {
            //std::cout << "recv error" << std::endl;
            return false;
        }
        return true;
    }

    void Send(int sock, const std::string str)
    {
        //std::cout << "send in" << std::endl;
        int n = send(sock, str.c_str(), str.size(), 0);
        if (n < 0)
            std::cout << "send error" << std::endl;
    }

    // lenth\r\nx_ op_ y_\r\n    // 10\r\nabc
    std::string Decode(std::string& buffer)
    {
        std::size_t pos = buffer.find(SEP);
        if (pos == std::string::npos) return "";
        int size = atoi(buffer.substr(0, pos).c_str());
        int surplus = buffer.size() - pos - 2 * SEP_LEN;
        if (surplus >= size)
        {
            // 至少具有一个合法完整的报文,可以动手提取了
            buffer.erase(0, pos + SEP_LEN);
            std::string s = buffer.substr(0, size);
            buffer.erase(0, size + SEP_LEN);
            return s;
        }
        else
        {
            return "";
        }
    }

    std::string EnCode(std::string& s)
    {
        std::string new_package = std::to_string(s.size());;
        new_package += SEP;
        new_package += s;
        new_package += SEP;
        return new_package;
    }
}